package com.zwh.se.collection.set;


import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * @author yexi
 *
 * Set是Collection子接口,Set的特点有,同时它的实现也拥有这些特点:
 * 1、不允许元素重复
 * 2、不会记录元素的添加先后顺序
 *
 * HashSet: HashSet做等值查询效率高
 * 开发中使用最多的Set实现类，底层采用哈希表实现,元素对象的hashCode值决定了在哈希表中的存储位置。
 * todo 当往HashSet集合中添加新的元素对象时，会先判断该对象和集合对象中的hashCode值：
 *      如果不等: 直接把该新的对象存储到hashCode指定的位置。
 *      如果相等: 再继续判断新对象和集合对象中的equals做比较。
 *          若equals为true ：视为是同一个对象，不保存。
 *          若equals为false：存储在之前对象同槽位的链表上。
 * 每一个存储到哈希表中的对象，都得覆盖hashCode和equals方法用来判断是否是同一个对象(一般会选择根据对象字段比较来判断)
 * (正常情况的设计下 equals 为 true 的时候 hashCode 也应该相等。)
 *
 * 所谓哈希表，本质上就是 数组 + 链表 = 哈希表
 * 关于哈希表,最重要的就是记住一个点。在哈希表中元素对象的hashCode和equals方法都很重要,所以如果要使用必须得重写hashcode和equals
 *
 * TIPS: HashSet 本质上是通过哈希表来实现的无序表(无序是相对于有序表而言的,指的是无法按照输入顺序进行输出)
 * TIPS: 在底层代码里,HashSet本质上更是基于HashMap来实现的,它是通过将值直接用作HashMap的key来实现的,而value则使用了一个固定值{@link HashSet#PRESENT})
 * TIPS: 正因如此,它们才会如此相像,所以HashMap的key拥有哪些特性HashSet就拥有哪些特性
 * TIPS: 又正因如此,Set相关的类将不会在这里探讨底层实现,相关底层实现解析本人将全部放置于讲解 Map相关的包处。
 *
 */
public class HashSetDemo {
    public static void main(String[] args) {
        Set hashSet = new HashSet();
        System.out.println("--------------------[1]新增操作--------------------");
        //boolean add(E e);
        hashSet.add(3);
        hashSet.add(5);
        System.out.println(hashSet.add(7));//true
        System.out.println(hashSet.add(5));//false,set无序且唯一,没法新增成功
        System.out.println(hashSet);//[3, 5, 7]

        System.out.println("--------------------[2]查询操作--------------------");
        //boolean isEmpty(); 判断 set 是不是空的,是空的返回true
        System.out.println(hashSet.isEmpty()); //false
        //boolean contains(Object o); 如果 set 中包含指定的元素，则返回 true。
        System.out.println(hashSet.contains(3)); //true

        System.out.println("--------------------[3]移除操作--------------------");
        //boolean remove(Object o); 判断是否移除成功
        hashSet.remove(3);
        System.out.println(hashSet);
        //hashSet.clear();清空 hashSet 内的所有元素,就不演示了

        System.out.println("--------------------[4]遍历操作--------------------");
        //不存在索引,没法使用普通的for循环

        //使用for-each遍历
        for (Object ele : hashSet) {
            System.out.print(ele + " ");
        }
        System.out.println();

        //使用迭代器来遍历(国内用得比较多)
        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()) {
            Object item = iterator.next();
            System.out.print(item + " ");
        }
        System.out.println();

        //对迭代器的优化(国外用得比较多)
        for (Iterator iterator2 = hashSet.iterator(); iterator2.hasNext(); ) {
            Object item = iterator2.next();
            System.out.print(item + " ");
        }
        System.out.println();

        System.out.println("--------------------[5]源码分析--------------------");
        /**
         * @see HashSet#HashSet()
         *         //可以看到 HashSet 的底层是通过 HashMap 来实现的
         *         map = new HashMap<>();
         */
        hashSet = new HashSet();
        /**
         * @see HashSet#PRESENT add()的时候作为固定的value值加入到hashMap当中
         * @see HashSet#add(Object e)
         *        //通过 hashMap 的put方法,将add的值作为key置入到hashMap当中,而value则采用了一个固定值
         *         return map.put(e, PRESENT)==null;
         */
        hashSet.add(null);
    }
}
